<!DOCTYPE html>
<html>
  <head>
    <title>testD3_chp14_1.html</title>
    
    <script src="https://d3js.org/d3.v5.js" type="text/javascript"></script>

	</script>
	

    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <svg width="960" height="600"></svg>
    <script>
    	var marge = {top:60,bottom:60,left:60,right:60}
    	var svg = d3.select("svg")
		//定义svg图标
		svg.append('svg:defs').append('svg:g')
			.attr('id', 'gr')
			.append('svg:path')
			.attr('d', 'M991.399017 982.081273A30.115326 30.115326 0 1 1 933.57759 993.82625h-1.505766a421.16284 421.16284 0 0 0-840.217607 0H90.34845a30.115326 30.115326 0 1 1-57.821426-11.744977 481.845223 481.845223 0 0 1 333.677816-417.398424 301.153264 301.153264 0 1 1 291.51636 0 482.357183 482.357183 0 0 1 333.677817 417.398424zM752.885631 301.173742a240.922611 240.922611 0 1 0-240.922611 240.922612 240.922611 240.922611 0 0 0 240.922611-240.922612z')
			.attr('fill', '#fff');
    	var width = svg.attr("width")
    	var height = svg.attr("height")
    	var g = svg.append("g")
    		.attr("transform","translate("+marge.top+","+marge.left+")");
    		
    	//设置一个color的颜色比例尺，为了让不同的扇形呈现不同的颜色
    	var colorScale = d3.scaleOrdinal()
    		.domain(d3.range(1000))
    		.range(d3.schemeCategory10);
    	
    	//新建一个力导向图
    var forceSimulation = d3.forceSimulation()
        .force("link", d3.forceLink().id(function (d) {return d.id;}).distance(100).strength(1))
        .force("charge", d3.forceManyBody())
        .force("center", d3.forceCenter(width / 2, height / 2));
    	
 function update(graph) {   		
    	//初始化力导向图，也就是传入数据
    	//生成节点数据
    	forceSimulation.nodes(graph.nodes)
    		.on("tick",ticked);//这个函数很重要，后面给出具体实现和说明
    	//生成边数据
    	forceSimulation.force("link")
    		.links(graph.links)
    		.distance(function(d){//每一边的长度
    			return 100;
    		});
    	//设置图形的中心位置	
    	forceSimulation.force("center")
    		.x(width/2)
    		.y(height/2);
    	//在浏览器的控制台输出
    	console.log(graph.nodes);
    	console.log(graph.links);
    	
    	//有了节点和边的数据后，我们开始绘制
    	//绘制边
    	var links = g.append("g")
    		.selectAll("line")
    		.data(graph.links)
    		.enter()
    		.append("line")
    		.attr("stroke",function(d,i){
    			return colorScale(i);
    		})
    		.attr("stroke-width",1);
    	var linksText = g.append("g")
    		.selectAll("text")
    		.data(graph.links)
    		.enter()
    		.append("text")
    		.text(function(d){
    			return d.relation;
    		})
    	
    	//绘制节点
    	//老规矩，先为节点和节点上的文字分组
    	var gs = g.selectAll(".circleText")
    		.data(graph.nodes)
    		.enter()
    		.append("g")
    		.attr("transform",function(d,i){
    			var cirX = d.x;
    			var cirY = d.y;
    			return "translate("+cirX+","+cirY+")";
    		})
    		.call(d3.drag()
    			.on("start",started)
    			.on("drag",dragged)
    			.on("end",ended)
    		);
    		
    	//绘制节点
    	var pointer = gs.append("circle")
    		.attr("r",13)
    		.attr("fill",function(d,i){
    			return colorScale(i);
    		})
			.attr("stroke","red")
			.attr("stroke-width",2)
			.on("click", function(d) {console.log(d)});
    	//文字
    	var text = gs.append("text");
			text.append("tspan")
			.attr("x",-16)
			.attr("y",-12)
			.text(function(d){
    			return d.data.name.substr(0,2)});
			text.append("tspan")
			.attr("x",-22)
			.attr("y",5)
			.text(function(d){
    			return d.data.name.substr(2,3)});
			text.append("tspan")
			.attr("x",-18)
			.attr("y",22)
			.text(function(d){
    			return d.data.name.substr(5,2) + (d.data.name.length > 7 ? "..." : "");});
				//定义图标分组，在gs上添加一个g分组
    	let iconGroup = gs.append("svg:g");
		iconGroup.append("svg:use")
    .attr('xlink:href', "#gr")//图标的id，带#
    .attr('transform', 'translate(0,0)scale(0.02)');//位置和放大缩小
    	function ticked(){
    		links
    			.attr("x1",function(d){return d.source.x;})
    			.attr("y1",function(d){return d.source.y;})
    			.attr("x2",function(d){return d.target.x;})
    			.attr("y2",function(d){return d.target.y;});
    			
    		linksText
    			.attr("x",function(d){
    			return (d.source.x+d.target.x)/2;
    		})
    		.attr("y",function(d){
    			return (d.source.y+d.target.y)/2;
    		});
    			
    		gs
    			.attr("transform",function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    	}
    	function started(d){
    		if(!d3.event.active){
    			forceSimulation.alphaTarget(0.8).restart();
    		}
    		d.fx = d.x;
    		d.fy = d.y;
    	}
    	function dragged(d){
    		d.fx = d3.event.x;
    		d.fy = d3.event.y;
    	}
    	function ended(d){
    		if(!d3.event.active){
    			forceSimulation.alphaTarget(0);
    		}
    		d.fx = null;
    		d.fy = null;
    	}
 }
		d3.json("HangZhouBank.json").then( function(custRels) {
			
			var nodeMap = {};
			var graph = {nodes: new Array(custRels.customers.length), links: new Array(custRels.customers.length)};
			for (i=0;i<custRels.customers.length;i++){
				var node = {
						id: custRels.customers[i].code,
						data: custRels.customers[i]
				}
				nodeMap[node.id] = node;
				graph.nodes[i] = node;
			}
			for (i=0;i<custRels.relations.length;i++){
				var edge = {
						source: nodeMap[custRels.relations[i].sourceCustomer],
						target: nodeMap[custRels.relations[i].targetCustomer],
						data: custRels.relations[i]
				}
				graph.links[i] = edge;
			}
			console.log("nodes:"+ graph.nodes.length);
			update(graph);
		})
    </script>
  </body>
</html>